#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Date    : 2022/3/21
# @Author  : jenkins
# @Version : V1.0
# @Features: 解析IPA信息

import zipfile
import plistlib
import subprocess
import json
import datetime
import sys,os,re


#转义后的模板-https://jsonformatter.org/json-escape
plistTemplate="""
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>items</key>
	<array>
		<dict>
			<key>assets</key>
			<array>
				<dict>
					<key>kind</key>
					<string>software-package</string>
					<key>url</key>
					<string>{{url}}</string>
				</dict>
				<dict>
					<key>kind</key>
					<string>display-image</string>
					<key>needs-shine</key>
					<integer>0</integer>
					<key>url</key>
					<string>https://s3.bmp.ovh/imgs/2022/03/09007d0d3d540969.png</string>
				</dict>
				<dict>
					<key>kind</key>
					<string>full-size-image</string>
					<key>needs-shine</key>
					<true/>
					<key>url</key>
					<string>https://s3.bmp.ovh/imgs/2022/03/09007d0d3d540969.png</string>
				</dict>
			</array>
			<key>metadata</key>
			<dict>
				<key>bundle-identifier</key>
				<string>{{bundle-identifier}}</string>
				<key>bundle-version</key>
				<string>{{bundle-version}}</string>
				<key>kind</key>
				<string>software</string>
				<key>title</key>
				<string>{{title}}</string>
			</dict>
		</dict>
	</array>
</dict>
</plist>
"""


# 解压ipa获取并信息
def unzip_ipa(path):
	ipa_file = zipfile.ZipFile(path)
	plist_path = find_path(ipa_file, 'Payload/[^/]*.app/Info.plist')
	# 读取plist内容
	plist_data = ipa_file.read(plist_path)
	# 解析plist内容
	plist_info = plistlib.loads(plist_data)
	
	# 获取mobileprovision文件路径
	provision_path = find_path(ipa_file, 'Payload/[^/]*.app/embedded.mobileprovision')
	provision_data = ipa_file.read(provision_path)
	mobileprovision_info=get_mobileprovision(provision_data)	
	return (plist_info,mobileprovision_info)


def get_mobileprovision(content):
		provision_xml_rx = re.compile(br'<\?xml.+</plist>', re.DOTALL)
		match = provision_xml_rx.search(content)
		if match:
			xml_content = match.group()
			data = plistlib.loads(xml_content)
			#移除无用信息（影响阅读~）			
			data.setdefault("DeveloperCertificates","")
			data.setdefault("DER-Encoded-Profile","")
			del data["DeveloperCertificates"]
			del data["DER-Encoded-Profile"]
			return data
		else:
			return None	
	
# 获取plist路径
def find_path(zip_file, pattern_str):
	name_list = zip_file.namelist()
	pattern = re.compile(pattern_str)
	for path in name_list:
		m = pattern.match(path)
		if m is not None:
			return m.group()
		
		
#二进制方式写入文件
def WriteFile(filePath,data):	
	if isinstance(data,bytes)==False:
		print("data is not bytes next encode")
		data=data.encode()
	file_obj = open(filePath,'wb')    
	file_obj.write(data)
	file_obj.close()
	
	

def replaceMultisubStr(rep,text):
	rep = dict((re.escape(k), v) for k, v in rep.items()) 
	pattern = re.compile("|".join(rep.keys()))
	text = pattern.sub(lambda m: rep[re.escape(m.group(0))], text)	
	return text
	
	
def make_plist(url, bundle_id, version, title):
	text=plistTemplate.strip()
	rep =  {
		"{{url}}":url,
		"{{bundle-identifier}}":bundle_id,
		"{{bundle-version}}":version,
		"{{title}}":title,
	}
	
	result=replaceMultisubStr(rep,text)
	#生成plist文件	
	WriteFile("./manifest.plist", result)
	


def make_indexHtml(title):
	htmlCode="""
	<!DOCTYPE html>
	<html>
		<head>
			<meta charset="UTF-8">
			<title></title>
		</head>
		<body>
			<h2 style="text-align:center;">应用名称</h2>
			<p class="download_content top-space" style="text-align: center;">  
				<a class="download_btn" style="font-size:20px;text-align:center;color:#69DEDA" href="itms-services://?action=download-manifest&url=https://gitee.com/huluo666/IPAInstall/raw/master/manifest.plist">点击下载</a>
			</p>  		
			<p class="title top-space" style="font-size:15px; text-align: center;">通过Safari打开链接，点击按钮下载安装</p> 
		</body>  
	</html>
	"""
	text=htmlCode.strip()
	rep =  {
		"应用名称":title,
	}
	result=replaceMultisubStr(rep,text)
	#生成plist文件	
	WriteFile("./index.html", result)

	
	

	
def string_subprocessPopen(command, cwd_patch, cancel_newline):
	command_file = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
									cwd=cwd_patch)
	command_file.wait()
	command_string = command_file.stdout.read().decode()
	if cancel_newline == True:
		command_string = command_string.replace("\n", '')
	return command_string
	

def dateConverter(o):
	if isinstance(o, datetime.datetime):
		return o.__str__()
	

def appMain(argv):
#	if len(sys.argv) < 2:        
#		print('请输入ipa地址参数')
#		exit()
#	script_name = sys.argv[0]  #脚本名称
#	ipaPath = sys.argv[1]  #IPA地址
	
	ipaPath="./otatest.ipa" #测试
	(plist_info,mobileprovision_info)=unzip_ipa(ipaPath)
	
	#打印信息	
	print('App名称: %s' % str(plist_info['CFBundleDisplayName']))
	print('包名 (Bundle ID): %s' % str(plist_info['CFBundleIdentifier']))
	print('版本号（Version）: %s' % str(plist_info['CFBundleShortVersionString']))
	print('版本号（Build）: %s' % str(plist_info['CFBundleVersion']))
	print('最低支持系统）: %s' % str(plist_info['MinimumOSVersion']))
	
	
	print("\n描述文件信息")
	mobileprovisionInfoJSON = json.dumps(mobileprovision_info,default=dateConverter)
	print(mobileprovisionInfoJSON)
	
	#创建plist和html文件	
	make_plist("https://huluo-1300517785.cos.ap-guangzhou.myqcloud.com/lnsdk.ipa",plist_info['CFBundleIdentifier'], plist_info['CFBundleShortVersionString'], plist_info['CFBundleDisplayName'])
	make_indexHtml(plist_info['CFBundleDisplayName'])
	
	
if __name__ == '__main__':
	appMain(sys.argv)
	